using System.Collections.Generic;

namespace SerialPortLibrary
{
    //---------------------modbus 协议示例----------------
    //从机地址1 01 发送到地址为01 的从机
    //功能码1 03 读取寄存器
    //起始地址2 0106 起始地址为0106H
    //数据长度2 0002 读取2 个寄存器（共4 字节）
    //CRC 码2 25F6 由主机计算出的CRC 码
    //从机（EDA）响应返回的报文格式：
    //从机响应字节数返回信息备注()
    //从机地址1 01 来至从机01
    //功能码1 03 读取寄存器
    //返回字节数1 04 2 个寄存器共4 字节
    //寄存器数据1 2 2710 地址为0106 寄存器的内容
    //寄存器数据2 2 1388 地址为0107 寄存器的内容
    //CRC 码2 FC14
    //-----------------------------------------------------------
    /// <summary>
    /// 标准Modbus协议驱动
    /// </summary>
    public class StandardModbusDriver : DataPublish,IDriver
    {
        internal StandardModbusDriver(IDataPublish publish)
        {
            publish.DataPublishEvent += DataPublish;
        }

        private bool DataPublish(object sender, DataPublishEventArgs e)
        {
            //发出通知--允许下一个命令发送
            StandardModbusSerialData data = e.data as StandardModbusSerialData;
            if (e.data.Error.ErrorType != 0)
            {
                //data.CurCommand.CompleteSign.Set();
                //data.CurCommand.FullPackageSign.Set();

                return false;
            }
            else
            {
                bool success = this.PickPacket(e.data);
                if (success)
                {
                    if (data.CurCommand.cmdList.Count < 1)
                    {
                        data.CurCommand.FullPackageSign.Set();
                    }
                    System.Threading.ThreadPool.QueueUserWorkItem((o) => DataProcess(e.data));
                }
                return success;
            }
        }

        /// <summary>
        /// 协议解析
        /// </summary>
        /// <param name="Data">模块返回的字节数据</param>
        /// <returns>解析好的原始数据</returns>
        /// <remarks>按照MODBUS协议的格式,将有效数据部分取出,格式限定部分去除</remarks>
        private byte[] Analyze(byte[] Data)
        {
            //拆分协议
            //首先计算校验和,校验正确后开始进行拆分
            if (Data.Length >= 5)
            {
                byte[] Tmp = new byte[Data.Length - 3 + 1];
                for (int i = 0; i <= Data.Length - 3; i++)
                {
                    Tmp[i] = Data[i];
                }
                CRC.CRCData CRCVal = CRC.CRCCaculate(Tmp);
                //如果校验和一致
                if (Data[Data.Length - 2] == CRCVal.CRCLow && Data[Data.Length - 1] == CRCVal.CRCHigh)
                {
                    return Tmp;
                }
                else
                {
                    return null;
                }
                //}
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 数据处理
        /// </summary>
        /// <param name="data"></param>
        public void DataProcess(ISerialData data)
        {
            byte[] by = this.Analyze(data.Data);
            data.Data = by;
            DataPublishEventArgs e = new DataPublishEventArgs(data); 
            OnDataPublishEvent(e);
        }
        /// <summary>
        /// 解析完整包,整包返回true;否则返回false
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public bool PickPacket(ISerialData data)
        {
            byte[] by = data.Data;
            if (by == null) { return false; }
            if (by.Length < 4) { return false; }
            //写入命令返回 
            //命令格式 设备地址(1)+功能码(1)+起始寄存器地址(2)+写入成功数量(2)+校验码(2)
            if (by[1] == 0x10 && by.Length == 8) { return true; }
            //读取命令返回
            //命令格式 设备地址(1)+功能码(1)+读取的字节数(1)+数据区+校验码(2)
            if (by[1] == 0x03 && (by[2] + 5 == by.Length)) { return true; }
            //固件升级 
            if (by[1] == 0x64)
            {
                if (by[3] == 0x2 && by.Length == 10) { return true; }
                if (by.Length == 8) { return true; }
            }
            return false;
        }
    }
}
